package com.huayi.server.NioServer;

import com.huayi.server.Dao.DeviceDao;
import com.huayi.server.Entity.DeviceEntity;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.util.concurrent.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

@ChannelHandler.Sharable
@Component
public class ServerHandler extends SimpleChannelInboundHandler<Message> {

    @Autowired
    DeviceDao deviceDao;

    Logger logger = LoggerFactory.getLogger(ServerHandler.class);

    private DeviceManager deviceManager;

    private Channel channel = null;

    Boolean ready = true;

    //用于获取结果
    AtomicInteger seq = new AtomicInteger(0xff0000);
    Map<Integer, Promise> commandResultMap = new ConcurrentHashMap<Integer, Promise>();

    public ServerHandler(){
        logger.info("ServerHandler construct ...");
    }

    public void setDeviceManager(DeviceManager deviceManager) {
        this.deviceManager = deviceManager;
    }

    @Override
    public void channelRegistered(ChannelHandlerContext channelHandlerContext) throws Exception {
        logger.info("channelRegistered");
        channel = channelHandlerContext.channel();
    }

    @Override
    public void channelUnregistered(ChannelHandlerContext channelHandlerContext) throws Exception {
        logger.info("channelUnregistered");
        ready = false;
    }

    @Override
    public void channelActive(ChannelHandlerContext channelHandlerContext) throws Exception {
        logger.info("channelActive");
    }

    @Override
    public void channelInactive(ChannelHandlerContext channelHandlerContext) throws Exception {
//        logger.info("channelInactive");
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, Message msg) throws Exception {
        switch (msg.getApi()){
            case 2://REPORT
                for (DeviceEntity deviceEntity : msg.getDevicelist()){
                    deviceManager.add(deviceEntity);
                }
                deviceDao.saveAll(msg.getDevicelist());
                break;
            case 4://LOGIN
                deviceManager.addHandler(msg.getDeviceid(),this);//命令中没有表示根节点ID
                break;
            case 5://HEART
                this.sendMessage(msg);
                break;
        }
    }


    @Override
    public void channelReadComplete(ChannelHandlerContext channelHandlerContext) throws Exception {
//        logger.info("channelReadComplete");
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext channelHandlerContext, Object o) throws Exception {
        channelHandlerContext.close();
    }

    @Override
    public void channelWritabilityChanged(ChannelHandlerContext channelHandlerContext) throws Exception {
        logger.info("channelWritabilityChanged");
    }

    @Override
    public void handlerAdded(ChannelHandlerContext channelHandlerContext) throws Exception {
        logger.info("handlerAdded");
    }

    @Override
    public void handlerRemoved(ChannelHandlerContext channelHandlerContext) throws Exception {
        logger.info("handlerRemoved");
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext channelHandlerContext, Throwable throwable) throws Exception {
        logger.info("exceptionCaught");
    }

    public Future<Boolean> sendMessage(Message message){
        if (channel == null || !channel.isActive()) {
            return new FailedFuture<>(GlobalEventExecutor.INSTANCE,new Throwable("channel is not available"));
//            return new FailedFuture<Boolean>(GlobalEventExecutor.INSTANCE, new RuntimeException(
//                    "channel is not available"));
        }
        ChannelFuture writeAndFlush = channel.writeAndFlush(message);

        DefaultPromise<Boolean> resultPromise = new DefaultPromise<>(GlobalEventExecutor.INSTANCE);

        writeAndFlush.addListener(future -> {
            if (future.isSuccess()){
                logger.info("write success...");
                resultPromise.setSuccess(true);
            }else{
                logger.error("write error...");
                resultPromise.setFailure(new Throwable("send error..."));
            }
        });
        return resultPromise;
    }

    public Future<Boolean> sendMessage(String string){
        logger.info("handler sendMessage：" + string);
        if (channel == null || !channel.isActive()) {
            return new FailedFuture<Boolean>(GlobalEventExecutor.INSTANCE, new RuntimeException(
                    "channel is not available"));
        }
        ChannelFuture writeAndFlush = channel.writeAndFlush(Unpooled.copiedBuffer(string.getBytes()));

        DefaultPromise<Boolean> resultPromise =
                new DefaultPromise<Boolean>(GlobalEventExecutor.INSTANCE);
        logger.info("发送控制指令：" + string);
        return resultPromise;
    }

}
